import { Scene, WebGLRenderer, PerspectiveCamera, DirectionalLight, Light, PointLight, AmbientLight, AxesHelper, BufferAttribute, OrthographicCamera, MeshBasicMaterial, DoubleSide, Mesh, PointsMaterial, Points, LineBasicMaterial, Line, BufferGeometry, MeshLambertMaterial, Group } from "three";
import * as THREE from "three";

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { PCDLoader } from "three/examples/jsm/loaders/PCDLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import group from "./lib/model";

class Manager3D {
    private scene: Scene;
    private camera: PerspectiveCamera;
    private renderer: WebGLRenderer;
    private controls: OrbitControls;

    constructor(threeRef: HTMLElement) {
        // 创建场景
        this.scene = new Scene();

        // 初始化
        this.setScene();
        // 设置相机    
        this.camera = this.setCamera(threeRef);
        // 设置渲染器
        this.renderer = this.setRenderer(threeRef);
        // 动作监听
        this.controls = this.addControl();
        // 启动渲染
        this.render();
    }

    // 场景
    setScene() {
        // // 创建网格模型
        // scene.add(this.createGeometry());

        // // 点渲染模式
        // scene.add(this.createPoints());

        // // 线条渲染模式
        // scene.add(this.createLine());

        this.scene.add(group);

        //点光源
        this.scene.add(this.createLight(new PointLight("#ffffff", 0.8), (point: Light) => point.position.set(1000, 1000, 1000)));

        // 平行光
        this.scene.add(this.createLight(new DirectionalLight("#ffffff", 0.7), (point: Light) => point.position.set(-400, -200, -300)));

        // //环境光
        this.scene.add(this.createLight(new AmbientLight("#444444")));

        // 创建坐标系
        this.scene.add(this.createAxis());
    }

    // 相机
    setCamera(threeRef: HTMLElement) {
        var width = threeRef.clientWidth; //窗口宽度
        var height = threeRef.clientHeight; //窗口高度
        var k = width / height; //窗口宽高比
        var s = 200; //三维场景显示范围控制系数，系数越大，显示的范围越大
        //创建相机对象
        let camera = new THREE.PerspectiveCamera(30, width / height, 1, 30000);

        camera.position.set(4000, 4000, 4000); //设置相机位置
        camera.up.set(0, 1, 0);
        camera.lookAt(0, 0, 0); //设置相机方向(指向的场景对象)
        // camera.up.set(0, 0, 1);

        return camera;
    }
    // 渲染器
    setRenderer(threeRef: HTMLElement) {
        let renderer = new WebGLRenderer();
        renderer.setSize(threeRef.clientWidth, threeRef.clientHeight);//设置渲染区域尺寸
        renderer.setClearColor("#cccccc", 1); //设置背景颜色
        threeRef.appendChild(renderer.domElement); //body元素中插入canvas对象
        return renderer;
    }
    // 渲染
    render() {
        this.renderer.render(this.scene, this.camera);
        // this.controls && this.controls.update();
        //监听鼠标、键盘事件
        requestAnimationFrame(this.render.bind(this));
    }
    // 鼠标和键盘事件
    addControl() {
        return new OrbitControls(this.camera, this.renderer.domElement);//创建控件对象
    }
    // 创建网格模型
    createGeometry() {
        let geometry = this.createSixPoint();

        // 三角面(网格)渲染模式
        var material = new MeshBasicMaterial({
            color: 0x0000ff, //三角面颜色
            side: DoubleSide //两面可见
        });
        //材质对象
        return new Mesh(geometry, material); //网格模型对象Mesh
    }
    // 点渲染模式
    createPoints() {
        let geometry = this.createSixPoint();

        // 点渲染模式
        var material = new PointsMaterial({
            color: 0xff0000,
            size: 10.0 //点对象像素尺寸
        }); //材质对象
        return new Points(geometry, material); //点模型对象
    }
    // 线条渲染模式
    createLine() {
        let geometry = this.createSixPoint();

        var material = new LineBasicMaterial({
            color: 0xff0000 //线条颜色
        });//材质对象
        return new Line(geometry, material);//线条模型对象
    }
    // 创建6个顶点
    createSixPoint() {
        var geometry = new BufferGeometry(); //创建一个Buffer类型几何体对象
        //类型数组创建顶点数据
        var vertices = new Float32Array([
            0, 0, 0, //顶点1坐标
            50, 0, 0, //顶点2坐标
            0, 100, 0, //顶点3坐标
            0, 0, 10, //顶点4坐标
            0, 0, 100, //顶点5坐标
            50, 0, 10, //顶点6坐标
        ]);
        // 创建属性缓冲区对象
        var attribue = new BufferAttribute(vertices, 3); //3个为一组，表示一个顶点的xyz坐标
        // 设置几何体attributes属性的位置属性
        geometry.attributes.position = attribue;
        return geometry;
    }
    // 创建光源
    createLight(point: Light, beforeAdd: Function = () => { }) {
        beforeAdd && beforeAdd(point);
        return point;
    }
    // 创建坐标系
    createAxis() {
        //辅助坐标系  参数250表示坐标系大小，可以根据场景大小去设置
        return new AxesHelper(2000);
    }
}

export default Manager3D;